home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Games / Tetris / Source / RCS / TetMatrix.m,v < prev    next >
Encoding:
Text File  |  1975-04-26  |  24.7 KB  |  1,233 lines

  1. head     1.8;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ;
  6. comment  @@;
  7.  
  8.  
  9. 1.8
  10. date     92.03.01.10.27.08;  author melling;  state Exp;
  11. branches ;
  12. next     1.7;
  13.  
  14. 1.7
  15. date     92.03.01.05.07.51;  author melling;  state Exp;
  16. branches ;
  17. next     1.6;
  18.  
  19. 1.6
  20. date     92.02.29.20.35.58;  author melling;  state Exp;
  21. branches ;
  22. next     1.5;
  23.  
  24. 1.5
  25. date     92.02.28.05.19.08;  author melling;  state Exp;
  26. branches ;
  27. next     1.4;
  28.  
  29. 1.4
  30. date     91.12.19.10.12.51;  author melling;  state Exp;
  31. branches ;
  32. next     1.3;
  33.  
  34. 1.3
  35. date     91.12.16.17.22.18;  author melling;  state Exp;
  36. branches ;
  37. next     1.2;
  38.  
  39. 1.2
  40. date     91.12.07.07.49.23;  author melling;  state Exp;
  41. branches ;
  42. next     1.1;
  43.  
  44. 1.1
  45. date     91.12.07.03.37.08;  author melling;  state Exp;
  46. branches ;
  47. next     ;
  48.  
  49.  
  50. desc
  51. @Tetris 1.1
  52. @
  53.  
  54.  
  55. 1.8
  56. log
  57. @Release 1.3
  58. @
  59. text
  60. @#import <appkit/NXImage.h>
  61. #import <ctype.h>
  62. #import <dpsclient/wraps.h>
  63. #import <math.h>
  64. #import <appkit/graphics.h>
  65. #import "TetMatrix.h"
  66. #import "Piece.h"
  67. #import "ScoreKeeper.h"
  68. #import "TetApp.h"
  69. #import "wraps.h"
  70.  
  71. // The number of pixels a block moves every step
  72. // Make it a divisor of the block size
  73. static const float ANM_DELTA  = 8.0;
  74.  
  75. const float GAMEOVER_BMAP_H = 100.0;
  76.  
  77. extern long random();
  78. extern void srandom(int seed);
  79. extern int getpid();
  80.  
  81. @@implementation TetMatrix
  82.  
  83. /*
  84.  * Some things should be set differently for color machines for either
  85.  * performances or aesthetic reasons.
  86.  */
  87. - initForColor
  88. {
  89.     const NXScreen *deepestScreen;
  90.  
  91.     deepestScreen=[NXApp colorScreen];
  92.  
  93.     if ( deepestScreen->depth  == NX_TwoBitGrayDepth ) {
  94.         anm_gameover_delta = 1.0;
  95.     } else {
  96.         anm_gameover_delta = 2.0;
  97.     }
  98.     return self;
  99. }
  100.  
  101.  
  102. - initFrame:(const NXRect *)frameRect
  103. {
  104.     NXSize size, interCell;
  105.     extern BOOL resize(NXSize *aSize);
  106.     float viewWidth, viewHeight;
  107.  
  108.     // Set the # of rows and columns in the view
  109.     [super initFrame:frameRect numRows:TETRIS_ROWS numCols:TETRIS_COLUMNS];
  110.     [self setBackgroundGray:NX_BLACK];
  111.  
  112.     size.width = size.height = 6.0;
  113.     [self setInset:&size];
  114.  
  115.     // Set the amount of space to leave b/w each block
  116.     interCell.width = interCell.height = 1.0; // 1 pixel
  117.     [self setIntercell:&interCell];
  118.  
  119.     pieceVisible = active = NO;
  120.     thePiece = [[Piece alloc] init];
  121.  
  122.     [thePiece getBlockSize:&size];
  123.  
  124.     // Should only resize in Piece.m
  125.     resize(&size);                      // Make sure block image isn't too large
  126.     [super setElementSize:&size];
  127.  
  128.     // Size Game View. 
  129.     // Default view size is (182, 438)
  130.     // Getting (176, 416)
  131.     viewWidth =  6. + TETRIS_COLUMNS * (size.width + interCell.width)  + 6.;
  132.     viewHeight = 6. + (TETRIS_ROWS)* (size.height + interCell.height) + 6.;
  133.  
  134. #ifdef DEBUG
  135.     fprintf(stderr, "Sizing the Tetris view to (%f,%f)\n", viewWidth, viewHeight);
  136. #endif
  137.     [self sizeTo: viewWidth :viewHeight];
  138.  
  139.     scoreKeeper = nil;
  140.  
  141.     anmBitmap = [[NXImage allocFromZone:[self zone]] initSize:&bounds.size];
  142.  
  143.     // Eventually want the background to be setable
  144.  
  145. //    anmBitmap = [NXImage initSize:&bounds.size];
  146. //    [anmBitmap useFromFile:"Snow.tiff"];
  147.     showNext = nil;
  148.     [self initForColor];
  149.  
  150.     gameRunning = NO;
  151.     srandom(getpid());              // Seed random # generator
  152.  
  153.     return self;
  154. }
  155.  
  156. - setupRandomFill:(int)max
  157. {
  158.     int    blockNum;
  159.     int    row, col;
  160.  
  161.     if (max > TETRIS_ROWS) max = TETRIS_ROWS;
  162.     if (max > 10) max = 10;
  163.     // fprintf (stderr, "Start random fill ...\n");
  164.     for (row = 0; row < max; row++) {
  165.         for (col = 0; col < TETRIS_COLUMNS; col++) {
  166.             if ((random () & 0x3) == 0) {   /* set 1/4 */
  167.                 blockNum = (random () & 0x3); // Rand num 0..3
  168.                 [super setBitmap: [thePiece getBlockImage:blockNum] at:row :col];
  169.             }
  170.         }
  171.     }
  172.     return self;
  173. }
  174.  
  175.  
  176. - (BOOL)acceptsFirstResponder
  177. {
  178.     return active;
  179. }
  180.  
  181. - drawSelf:(const NXRect *)rects :(int)rectCount
  182. {
  183.     [super drawSelf:rects :rectCount];
  184.     if (pieceVisible) {
  185.         NXRectClip(&insetBounds);
  186.         [thePiece draw:self];
  187.     }
  188.     return self;
  189. }
  190.  
  191.  
  192. /*
  193.  *  Act upon keyboard input from the user.
  194.  *
  195.  */
  196. - keyDown:(NXEvent *)theEvent
  197. {
  198.     unsigned short charCode;
  199.  
  200.     charCode = theEvent->data.key.charCode;
  201.     if (isupper(charCode))
  202.       charCode = tolower(charCode);
  203.  
  204.     switch (charCode) {
  205.     case 'k':
  206.     case '5':
  207.         if (charCode == 'k' || theEvent->flags & NX_NUMERICPADMASK)
  208.           [thePiece turn:self];
  209.         break;
  210.     case 'j':
  211.     case '4':
  212.         if (charCode == 'j' || theEvent->flags & NX_NUMERICPADMASK)
  213.           [thePiece left:self];
  214.         break;
  215.         
  216.     case 'l':
  217.     case '6':
  218.         if (charCode == 'l' || theEvent->flags & NX_NUMERICPADMASK)
  219.           [thePiece right:self];
  220.         break;
  221.  
  222.     case ' ':
  223.     case '2':
  224.     case '0':
  225.         if (charCode == ' ' || theEvent->flags & NX_NUMERICPADMASK) {
  226.             [self stopTimedEntry];
  227.             [thePiece drop:self];
  228.             [self startTimedEntry];
  229.         }
  230.         break;
  231.  
  232.      case 13:                          // Pause if the user hits return
  233.         [NXApp pause:self];
  234.     }
  235.     return self;
  236. }
  237.  
  238.  
  239. - setPieceVisible:(BOOL)flag
  240. {
  241.     pieceVisible = flag;
  242.     return self;
  243. }
  244.  
  245. - setScoreKeeper:keeper
  246. {
  247.     scoreKeeper = keeper;
  248.     return self;
  249. }
  250.  
  251. /*
  252.  *  Determine how fast a piece will drop.
  253.  */
  254. -(double) newDelay
  255. {
  256.     return 0.5 - 0.1 * sqrt(2.5 * level);
  257. }
  258.  
  259. - newGame:(int)theLevel
  260. {
  261.     [[super setBitmap:nil] display];
  262.     [window makeFirstResponder:self];
  263.     [self setPieceVisible:YES];
  264.     [thePiece reset:self
  265.        piece:((showNext) ? [showNext pieceInfo] : PIECE_INFO_NULL)];
  266.  
  267.     [self setupRandomFill:[randomFields intValue]];
  268.     [self display];
  269.     level = (float)theLevel;
  270.     teDelay = [self newDelay];
  271.     [self startTimedEntry];
  272.     active = YES;
  273.     return self;
  274. }
  275.  
  276. - pause:sender
  277. {
  278.     // Make TetApp the first responder
  279.     [window makeFirstResponder:window];
  280.     // Will making this object the first responder cause problems?
  281. //    [window makeFirstResponder:self];
  282.     active = NO;
  283.     return [self stopTimedEntry];
  284. }
  285.  
  286.  
  287. - continue:sender
  288. {
  289.     active = YES;
  290.     [window makeFirstResponder:self];
  291.     return [self startTimedEntry];
  292. }
  293.  
  294. - stop:sender
  295. {
  296.     active = NO;
  297.     [window makeFirstResponder:window];
  298.     return [self stopTimedEntry];
  299. }
  300.  
  301. /*
  302.  * Scroll "Game Over" down the screen after the game is finished.
  303.  */
  304. - animateGameOver
  305. {
  306.     NXSize tmpSize;
  307.     id anmGameOver;
  308.     NXRect destRect, unionRect;
  309.     
  310.     tmpSize.height = GAMEOVER_BMAP_H;
  311.     tmpSize.width = insetBounds.size.width;
  312.     anmGameOver = [[NXImage alloc] initSize:&tmpSize];
  313.  
  314.     // Composite "Game Over" to a window
  315.     [anmGameOver lockFocus];
  316.     PSsetalpha(0.0);
  317.     PSrectfill(0.0, 0.0, insetBounds.size.width, GAMEOVER_BMAP_H);
  318.     PSsetalpha(1.0);
  319.     PSgameover(insetBounds.size.width);
  320.     [anmGameOver unlockFocus];
  321.     
  322.     [super getRect:&destRect for:(int)(TETRIS_ROWS / 2) :0];
  323.     [super getRect:&unionRect for:TETRIS_ROWS - 1 :TETRIS_COLUMNS - 1];
  324.     NXUnionRect(&unionRect, &destRect);
  325.  
  326.     [anmBitmap lockFocus];
  327.     [self drawSelf:&destRect :1];
  328.     [anmBitmap unlockFocus];
  329.     
  330.     NXSetRect(&unionRect, destRect.origin.x, unionRect.origin.y,
  331.                  destRect.size.width, GAMEOVER_BMAP_H);
  332.     [self lockFocus];
  333.     NXRectClip(&destRect);
  334.  
  335.     while (unionRect.origin.y - anm_gameover_delta >= destRect.origin.y) {
  336.         unionRect.origin.y -= anm_gameover_delta;
  337.         
  338.         [anmGameOver composite:NX_SOVER toPoint:&unionRect.origin];
  339.         [[self window] flushWindow];
  340.         NXPing();
  341.         // Redraw the background to erase the "Game Over" letters 
  342. //        [anmBitmap composite:NX_COPY fromRect:&unionRect toPoint:&unionRect.origin];
  343.         [anmBitmap composite:NX_SOVER fromRect:&unionRect toPoint:&unionRect.origin];
  344.         NXPing();
  345.     }
  346.     [anmGameOver composite:NX_SOVER toPoint:&unionRect.origin];
  347.     [self unlockFocus];
  348.     
  349.     [anmGameOver free];
  350.     return self;
  351. }
  352.  
  353. /* The following methods: 
  354.  *   Animate a piece dropping.
  355.  *   Dissolve filled rows.
  356.  *   Removes filled rows from the game.
  357.  */
  358.  
  359. - (BOOL) rowFilled:(int)row
  360. {
  361.     int xc;
  362.  
  363.     for (xc = 0; xc < TETRIS_COLUMNS; xc++)
  364.         if (![super bitmapAt:row :xc])
  365.         break;
  366.     return (xc == TETRIS_COLUMNS);
  367. }
  368.  
  369. - (BOOL) rowEmpty:(int) row
  370. {
  371.     int xc;
  372.  
  373.     for (xc = 0; xc < TETRIS_COLUMNS; xc++)
  374.       if ([super bitmapAt:row :xc])
  375.         break;
  376.     return (xc == TETRIS_COLUMNS);
  377. }
  378.  
  379. - fadeFilledRows:(int) from :(int) to
  380. {
  381.     float gc;
  382.     NXRect destRect;
  383.     NXRect unionRect;
  384.     
  385.     [super getRect:&destRect for:from :0];
  386.     [super getRect:&unionRect for:to :TETRIS_COLUMNS - 1];
  387.     NXUnionRect(&unionRect, &destRect);
  388.  
  389.     // Composite the rows we are about to fade to anmBitmap
  390.     [anmBitmap lockFocus];
  391.     [self drawSelf:&destRect :1];
  392.     [anmBitmap unlockFocus];
  393.  
  394.     // Fade the blocks
  395.     [self lockFocus];
  396.     for (gc = 1.0; gc > 0.3; gc -= .03) {
  397.         PSsetgray(gc);
  398.         PScompositerect(destRect.origin.x, destRect.origin.y, destRect.size.width,
  399.                              destRect.size.height, NX_PLUSD);
  400.         [[self window] flushWindow];
  401.         // Now redraw the blocks so we can fade them a little more
  402. //        [anmBitmap composite:NX_COPY fromRect:&destRect toPoint:&destRect.origin];
  403.         [anmBitmap composite:NX_SOVER fromRect:&destRect toPoint:&destRect.origin];
  404.         NXPing();
  405.     }
  406.     // Now make the blocks totally disappear.
  407.     PSsetgray(NX_BLACK);
  408.     PScompositerect(destRect.origin.x, destRect.origin.y, destRect.size.width,
  409.                          destRect.size.height, NX_SOVER);
  410. //                         destRect.size.height, NX_COPY);
  411.  
  412.     [self unlockFocus];
  413.  
  414.     return self;
  415. }
  416.  
  417. /*
  418.  * Move the pieces as they are moved down on the screen after one or more rows
  419.  * has been cleared.
  420.  */
  421. - animateDrop:(int) firstFullRow :(int)firstNonFullRow :(int) lastNonEmptyRow
  422. {
  423.     NXPoint dPt;
  424.     NXRect destRect;
  425.     NXRect unionRect;
  426.  
  427.     [super point:&dPt for:firstFullRow :0]; // Place where to put falling blocks
  428.     [super getRect:&destRect for:firstNonFullRow :0];    // First row to move down
  429.     // Last row to move down
  430.     [super getRect:&unionRect for:lastNonEmptyRow :TETRIS_COLUMNS - 1];
  431.  
  432.     // We want to move everything down from the last non-full row to
  433.     // the last row with a piece in it.
  434.  
  435.     NXUnionRect(&unionRect, &destRect);
  436.     unionRect = destRect;
  437.  
  438.     // Create the image of the blocks
  439.     [anmBitmap lockFocus];
  440.     [self drawSelf:&destRect :1];
  441.     [anmBitmap unlockFocus];
  442.  
  443.     [self lockFocus];
  444.  
  445.     PSsetgray(NX_BLACK);              // The destination Rect is Black
  446.     PScompositerect(destRect.origin.x, destRect.origin.y, destRect.size.width,
  447.                          destRect.size.height, NX_COPY);
  448.  
  449.  
  450.     while (unionRect.origin.y - ANM_DELTA > dPt.y) {
  451.  
  452.         unionRect.origin.y -= ANM_DELTA;
  453.  
  454.         // First clear the window
  455.         [anmBitmap composite:NX_COPY fromRect:&destRect toPoint:&unionRect.origin];
  456.         [[self window] flushWindow];
  457.         PScompositerect(unionRect.origin.x, unionRect.origin.y, unionRect.size.width,
  458.                              unionRect.size.height, NX_COPY);
  459.         NXPing();
  460.     }
  461.     [anmBitmap composite:NX_COPY fromRect:&destRect toPoint:&dPt];
  462.     [[self window] flushWindow];
  463.  
  464.     //    NXPing();
  465.     [self unlockFocus];
  466.     return self;
  467. }
  468.  
  469. /*
  470.  *  Remove the filled rows after they have dissolved
  471.  */
  472. - removeFilledRows
  473. {
  474.     BOOL filled;
  475.     int ycfrom, ycto, yctop;
  476.     int xc, yc;
  477.     int lastFilledRow, lastNonEmptyRow, firstFilled;
  478.     int piecey = [thePiece getCurRow]; // Get the bottom-most row of the piece.
  479.  
  480.     do {
  481.         filled = NO;                  // This should only execute once?!?!
  482.  
  483.         // Work our way up from the current piece's row.
  484.         for (ycfrom = piecey; ycfrom < piecey + MAX_SHAPE_SIZE; ycfrom++) {
  485.             if ([self rowFilled: ycfrom]) {
  486.                 filled = YES;
  487.                 firstFilled = ycfrom;
  488.                 break;
  489.             }
  490.         }
  491.  
  492.         if (filled) {
  493.  
  494.             // Find the first row that isn't completely filled.
  495.             lastFilledRow = firstFilled;    // Loop can execute 0 times  
  496.             for (ycto = firstFilled + 1; ycto < firstFilled + MAX_SHAPE_SIZE; ycto++) {
  497.                 if ([self rowFilled: ycto]) {
  498.                     lastFilledRow = ycto;
  499.                 } else {
  500.                     break;
  501.                 }
  502.             }
  503.             // Find the topmost row in the program.  A row with at least one block.
  504.             // Assert: Must enter loop at least once.
  505.             for (yctop = lastFilledRow+1; yctop < TETRIS_ROWS; yctop++) {
  506.                 if (! [self rowEmpty: yctop]) {
  507.                     lastNonEmptyRow = yctop; // But do I have to execute this once?
  508.                 } else {
  509.                     break;
  510.                 }
  511.             }
  512.             [self fadeFilledRows: firstFilled :lastFilledRow];
  513.  
  514.             // Animate the all of the pieces as the move down.
  515.             [self animateDrop:firstFilled :lastFilledRow+1 :lastNonEmptyRow];
  516.  
  517.  
  518.             // Move the rows above the faded rows down to take their place.
  519.  
  520.             for (yc = lastFilledRow+1; yc <=lastNonEmptyRow; yc++) {
  521.                 for (xc = 0; xc < TETRIS_COLUMNS; xc++) // For each block in the row.
  522.                   [super setBitmap:[self bitmapAt:yc :xc] at:firstFilled :xc];
  523.                 firstFilled++;
  524.             }
  525.  
  526.             // Clear the rows at the very top that have been moved down
  527.             // and which have nothing to take their place.
  528.  
  529.             for (yc = firstFilled; yc <=lastNonEmptyRow; yc++) {
  530. #ifdef DEBUG
  531.                 printf("Removing row %d\n", yc); 
  532. #endif
  533.                 for (xc = 0; xc < TETRIS_COLUMNS; xc++)
  534.                   [super setBitmap:nil at:yc :xc];
  535.             }
  536.             piecey++;
  537.         }
  538.     } while (filled);
  539.     return self;
  540. }
  541.  
  542.  
  543. /* The main animation routines follow.  A timed entry routine is setup
  544.  * so that it calls teHandler at a regular interval (depending on the
  545.  * level)
  546.  */
  547.  
  548. /*
  549.  *  The timed entry handler that gets called every teDelay seconds.
  550.  *
  551.  */
  552. - step
  553. {
  554.     static int downWait = 0;
  555.  
  556.     // Move the piece down.  If it can't move down make it stick,
  557.     // remove filled rows, and generate a new piece.
  558.  
  559.     if (![thePiece down:self]) {
  560.  
  561.         // After the piece sticks to the bottom, wait for a while before
  562.         // we send the next piece.  The wait depends on the current level.
  563.  
  564.         if (++downWait >= level) {    // Don't commit the piece immediately
  565.             downWait = 0;
  566.             [self stopTimedEntry];
  567.             [self setPieceVisible:NO];
  568.             [thePiece stick:self]; // Make the piece stick
  569.             [self removeFilledRows];
  570.             [self setPieceVisible:YES];
  571.             if (scoreKeeper) {
  572.                 [scoreKeeper addScore:[thePiece points]];
  573.                 level += (MAX_LEVEL - level) / 400.0;
  574.                 teDelay = [self newDelay];
  575.             }
  576.             // show the next piece.
  577.             if ([thePiece reset:self piece:((showNext) ?
  578.                                       [showNext pieceInfo] : PIECE_INFO_NULL)])
  579.               [self startTimedEntry];
  580.             else {
  581.                 [self animateGameOver];
  582.                 [[self window] makeFirstResponder:[self window]];
  583.                 active = NO;
  584.                 [NXApp gameOver];
  585.             }
  586.         }
  587.  
  588.     } else {                              // The piece can't go down
  589.         downWait = 0;                  // Set a delay before showing next piece
  590.     }
  591.     return self;
  592. }
  593.  
  594. static void runOneStep (DPSTimedEntry timedEntry, double timeNow, void *data)
  595. {
  596.     [(id)data step];
  597. }
  598.  
  599. - startTimedEntry
  600. {
  601.     if (!gameRunning) {
  602.         timedEntryNum = DPSAddTimedEntry(teDelay,&runOneStep,
  603.                                                     self, NX_BASETHRESHOLD);
  604.         gameRunning = YES;
  605.     }
  606.     return self;
  607. }
  608.  
  609. - stopTimedEntry
  610. {
  611.     if (gameRunning) {
  612.         DPSRemoveTimedEntry(timedEntryNum);
  613.         gameRunning = NO;
  614.     }
  615.     return self;
  616. }
  617.  
  618. /*
  619.  * Clean up.
  620.  */
  621. - free
  622. {
  623.     [thePiece free];
  624.     [anmBitmap free];
  625.     return [super free];
  626. }
  627.  
  628. @@end
  629. @
  630.  
  631.  
  632. 1.7
  633. log
  634. @*** empty log message ***
  635. @
  636. text
  637. @d207 2
  638. a208 1
  639.     [self setupRandomFill:4];          // should be made user selectable
  640. d219 2
  641. a220 1
  642. //    [window makeFirstResponder:window];
  643. d222 1
  644. a222 1
  645.     [window makeFirstResponder:self];
  646. @
  647.  
  648.  
  649. 1.6
  650. log
  651. @*** empty log message ***
  652. @
  653. text
  654. @a16 1
  655. const float ANM_GAMEOVER_DELTA = .0;
  656. d24 19
  657. d88 2
  658. a89 1
  659. //    showNext = nil;
  660. d97 4
  661. d102 15
  662. d171 4
  663. d207 1
  664. a215 1
  665.  
  666. d218 3
  667. a220 1
  668.     [window makeFirstResponder:window];
  669. d274 2
  670. a275 2
  671.     while (unionRect.origin.y - ANM_GAMEOVER_DELTA >= destRect.origin.y) {
  672.         unionRect.origin.y -= ANM_GAMEOVER_DELTA;
  673. d279 2
  674. a280 1
  675. //        NXPing();
  676. d283 1
  677. a283 1
  678. //        NXPing();
  679. d515 1
  680. @
  681.  
  682.  
  683. 1.5
  684. log
  685. @*** empty log message ***
  686. @
  687. text
  688. @d42 6
  689. a47 1
  690.     [[NXImage findImageNamed:"MonoBlock1"] getSize:&size];
  691. a61 5
  692.     // Make the Window the proper size
  693.     [[self window] sizeWindow: viewWidth+104. :viewHeight+15.];
  694.  
  695.     pieceVisible = active = NO;
  696.     thePiece = [[Piece alloc] init];
  697. d238 1
  698. a238 1
  699.         NXPing();
  700. @
  701.  
  702.  
  703. 1.4
  704. log
  705. @*** empty log message ***
  706. @
  707. text
  708. @d13 3
  709. a15 1
  710. static const float ANM_DELTA  = 8.0;// Make it a divisor of the block size
  711. d17 1
  712. a17 1
  713. const float ANM_GAMEOVER_DELTA = 1.0;
  714. d27 3
  715. a29 1
  716.     NXSize size;
  717. d31 1
  718. a33 4
  719.     [[NXImage findImageNamed:"Block1"] getSize:&size];
  720.     resize(&size);                      // Make sure image isn't too large
  721.     [self setElementSize:&size];
  722.     [self sizeTo: (10*size.width) +(10) +6.  :(25*size.height)+ 10. +6.];
  723. d39 2
  724. a40 2
  725.     size.width = size.height = 1.0; // 1 pixel
  726.     [self setIntercell:&size];
  727. d42 18
  728. d65 3
  729. d71 1
  730. d73 2
  731. a74 1
  732.     srandom(getpid());
  733. d94 5
  734. a137 1
  735.  
  736. d247 1
  737. a247 1
  738. /* The following methods 
  739. @
  740.  
  741.  
  742. 1.3
  743. log
  744. @*** empty log message ***
  745. @
  746. text
  747. @d30 1
  748. d32 1
  749. d47 1
  750. a47 1
  751.     [anmBitmap useFromFile:"Snow.tiff"];
  752. a53 8
  753. /*
  754.  * Tell the Piece object about the Cheater object
  755.  */
  756. - setCheater:anObject
  757. {
  758.     [thePiece setCheater: anObject];    // Just pass it on.
  759.     return self;
  760. }
  761. d109 1
  762. d208 1
  763. a208 1
  764.         [anmBitmap composite:NX_COPY fromRect:&unionRect toPoint:&unionRect.origin];
  765. d210 1
  766. a210 1
  767. //        NXPing();
  768. d255 1
  769. d260 1
  770. d267 1
  771. d272 1
  772. d293 3
  773. a295 2
  774.     [super point:&dPt for:firstFullRow :0];
  775.     [super getRect:&destRect for:firstNonFullRow :0];
  776. d304 1
  777. d310 1
  778. a310 1
  779. //#ifdef FOO
  780. a313 1
  781. //#endif
  782. d315 1
  783. d317 1
  784. d369 1
  785. d373 1
  786. a373 1
  787.                     lastNonEmptyRow = yctop;
  788. a401 2
  789. //            [self display:&destRect :1];
  790. //            NXPing();
  791. @
  792.  
  793.  
  794. 1.2
  795. log
  796. @Tetris 1.2
  797. @
  798. text
  799. @a0 1
  800.  
  801. d12 4
  802. a15 3
  803. #define ANM_DELTA        8.0
  804. #define GAMEOVER_BMAP_H        100.0
  805. #define ANM_GAMEOVER_DELTA    1.0
  806. d26 1
  807. a26 1
  808.    
  809. d31 1
  810. d34 3
  811. a36 1
  812.     size.width = size.height = 1.0;
  813. d38 1
  814. a41 1
  815.     anmBitmap = [NXImage newSize:&bounds.size];
  816. d43 5
  817. a47 3
  818.     showNext = nil;
  819.     teRunning = NO;
  820.     colorWindow = [window canStoreColor];
  821. d52 9
  822. a78 2
  823.     BOOL abc=YES;
  824.     NXWindowDepth depth;
  825. a79 3
  826.     abc = [window canStoreColor];
  827.     depth = [window depthLimit];
  828.  
  829. d130 1
  830. a130 1
  831. -(double) newDelay:(float) level
  832. d144 1
  833. a144 1
  834.     teDelay = [self newDelay:level];
  835. d180 1
  836. a180 1
  837.     NXRect dRect, uRect;
  838. d194 4
  839. a197 3
  840.     [self getRect:&dRect for:(int)(TETRIS_ROWS / 2) :0];
  841.     [self getRect:&uRect for:TETRIS_ROWS - 1 :TETRIS_COLUMNS - 1];
  842.     NXUnionRect(&uRect, &dRect);
  843. d199 1
  844. a199 1
  845.     [self drawSelf:&dRect :1];
  846. d202 2
  847. a203 2
  848.     NXSetRect(&uRect, dRect.origin.x, uRect.origin.y,
  849.                  dRect.size.width, GAMEOVER_BMAP_H);
  850. d205 6
  851. a210 4
  852.     NXRectClip(&dRect);
  853.     while (uRect.origin.y - ANM_GAMEOVER_DELTA >= dRect.origin.y) {
  854.         uRect.origin.y -= ANM_GAMEOVER_DELTA;
  855.         [anmGameOver composite:NX_SOVER toPoint:&uRect.origin];
  856. d212 4
  857. a215 2
  858.         NXPing();
  859.         [anmBitmap composite:NX_COPY fromRect:&uRect toPoint:&uRect.origin];
  860. d217 1
  861. a217 1
  862.     [anmGameOver composite:NX_SOVER toPoint:&uRect.origin];
  863. d225 3
  864. a227 3
  865.  *   animate a piece dropping
  866.  *   dissolve filled rows
  867.  *   removes filled rows from the game.
  868. d230 1
  869. a230 1
  870. static BOOL rowFilled(id self, int row)
  871. d235 1
  872. a235 1
  873.         if (![self bitmapAt:row :xc])
  874. d240 1
  875. a240 1
  876. static BOOL rowEmpty(id self, int row)
  877. d243 1
  878. a243 1
  879.     
  880. d245 1
  881. a245 1
  882.       if ([self bitmapAt:row :xc])
  883. d253 2
  884. a254 2
  885.     NXRect dRect;
  886.     NXRect uRect;
  887. d256 8
  888. a263 8
  889.     [self getRect:&dRect for:from :0];
  890.     [self getRect:&uRect for:to :TETRIS_COLUMNS - 1];
  891.     NXUnionRect(&uRect, &dRect);
  892.     
  893.     [self->anmBitmap lockFocus];
  894.     [self drawSelf:&dRect :1];
  895.     [self->anmBitmap unlockFocus];
  896.     
  897. d267 5
  898. a271 4
  899.         PScompositerect(dRect.origin.x, dRect.origin.y, dRect.size.width,
  900.                              dRect.size.height, NX_PLUSD);
  901.         [self->window flushWindow];
  902.         [self->anmBitmap composite:NX_COPY fromRect:&dRect toPoint:&dRect.origin];
  903. d275 4
  904. a278 2
  905.     PScompositerect(dRect.origin.x, dRect.origin.y, dRect.size.width,
  906.                          dRect.size.height, NX_COPY);
  907. d280 1
  908. d284 5
  909. a288 1
  910. - animateDrop:(int) from  :(int)to :(int) top
  911. d291 2
  912. a292 8
  913.     NXRect dRect;
  914.     NXRect uRect;
  915.     
  916.     [self point:&dPt for:from :0];
  917.     [self getRect:&dRect for:to :0];
  918.     [self getRect:&uRect for:top :TETRIS_COLUMNS - 1];
  919.     NXUnionRect(&uRect, &dRect);
  920.     uRect = dRect;
  921. d294 10
  922. d305 1
  923. a305 1
  924.     [self drawSelf:&dRect :1];
  925. d307 1
  926. a307 1
  927.     
  928. d309 11
  929. a319 6
  930.     PSsetgray(NX_BLACK);
  931.     PScompositerect(dRect.origin.x, dRect.origin.y, dRect.size.width,
  932.                          dRect.size.height, NX_COPY);
  933.     while (uRect.origin.y - ANM_DELTA > dPt.y) {
  934.         uRect.origin.y -= ANM_DELTA;
  935.         [anmBitmap composite:NX_COPY fromRect:&dRect toPoint:&uRect.origin];
  936. d321 2
  937. a322 2
  938.         PScompositerect(uRect.origin.x, uRect.origin.y, uRect.size.width,
  939.                              uRect.size.height, NX_COPY);
  940. d325 1
  941. a325 1
  942.     [anmBitmap composite:NX_COPY fromRect:&dRect toPoint:&dPt];
  943. d341 3
  944. a343 2
  945.     int piecey = [thePiece y];
  946.     
  947. d345 11
  948. a355 6
  949.         filled = NO;
  950.         for (ycfrom = piecey; ycfrom < piecey + MAX_SHAPE_SIZE; ycfrom++)
  951.           if (rowFilled(self, ycfrom)) {
  952.               filled = YES;
  953.               break;
  954.           }
  955. a356 12
  956.             for (ycto = ycfrom + 1; ycto < ycfrom + MAX_SHAPE_SIZE; ycto++)
  957.               if (!rowFilled(self, ycto))
  958.                  break;
  959.             for (yctop = ycto; yctop < TETRIS_ROWS; yctop++)
  960.               if (rowEmpty(self, yctop))
  961.                  break;
  962.             
  963.             [self fadeFilledRows: ycfrom :ycto - 1];
  964.             [self animateDrop:ycfrom :ycto :yctop - 1];
  965.             //        [self getRect:&uRect for:ycfrom :0];
  966.             //        [self getRect:&dRect for:yctop :TETRIS_COLUMNS - 1];
  967.             //        NXUnionRect(&uRect, &dRect);
  968. d358 38
  969. a395 1
  970.             for (yc = ycto; yc < yctop; yc++) {
  971. d397 1
  972. a397 2
  973.                   [super setBitmap:[self bitmapAt:yc :xc] at:ycfrom :xc];
  974.                 ycfrom++;
  975. d399 2
  976. a400 6
  977.             for (yc = ycfrom; yc < yctop; yc++)
  978.               for (xc = 0; xc < TETRIS_COLUMNS; xc++)
  979.                  [super setBitmap:nil at:yc :xc];
  980.             
  981.             //        [self display:&dRect :1];
  982.             //        NXPing();
  983. d420 4
  984. a423 1
  985.     
  986. d429 1
  987. a429 1
  988.         if (++downWait >= level) {
  989. d433 1
  990. a433 1
  991.             [thePiece stick:self];
  992. d439 1
  993. a439 1
  994.                 teDelay = [self newDelay: level];
  995. d451 3
  996. a453 2
  997.     } else {                              // The piece can go down
  998.         downWait = 0;
  999. a462 1
  1000.  
  1001. d465 4
  1002. a468 3
  1003.     if (!teRunning) {
  1004.         timedEntryNum = DPSAddTimedEntry(teDelay,&runOneStep,self, NX_BASETHRESHOLD);
  1005.         teRunning = YES;
  1006. d475 1
  1007. a475 1
  1008.     if (teRunning) {
  1009. d477 1
  1010. a477 1
  1011.         teRunning = NO;
  1012. @
  1013.  
  1014.  
  1015. 1.1
  1016. log
  1017. @Initial revision
  1018. @
  1019. text
  1020. @d6 1
  1021. d36 1
  1022. a36 1
  1023.     thePiece = [Piece new];
  1024. d42 1
  1025. a42 1
  1026.  
  1027. d65 2
  1028. d68 3
  1029. d105 111
  1030. d236 1
  1031. a236 1
  1032. static void fadeFilledRows(id self, int from, int to)
  1033. d263 1
  1034. d266 1
  1035. a266 1
  1036. static void animateDrop(id self, int from, int to, int top)
  1037. a267 1
  1038.     NXCoord yc;
  1039. d277 2
  1040. a278 2
  1041.     
  1042.     [self->anmBitmap lockFocus];
  1043. d280 1
  1044. a280 1
  1045.     [self->anmBitmap unlockFocus];
  1046. d288 2
  1047. a289 2
  1048.         [self->anmBitmap composite:NX_COPY fromRect:&dRect toPoint:&uRect.origin];
  1049.         [self->window flushWindow];
  1050. d294 2
  1051. a295 2
  1052.     [self->anmBitmap composite:NX_COPY fromRect:&dRect toPoint:&dPt];
  1053.     [self->window flushWindow];
  1054. d299 1
  1055. d302 3
  1056. a304 1
  1057.  
  1058. a310 2
  1059.     NXRect dRect;
  1060.     NXRect uRect;
  1061. d327 2
  1062. a328 2
  1063.             fadeFilledRows(self, ycfrom, ycto - 1);
  1064.             animateDrop(self, ycfrom, ycto, yctop - 1);
  1065. d335 1
  1066. a335 1
  1067.                   [self setBitmap:[self bitmapAt:yc :xc] at:ycfrom :xc];
  1068. d340 1
  1069. a340 1
  1070.                  [self setBitmap:nil at:yc :xc];
  1071. a349 5
  1072. - setPieceVisible:(BOOL)flag
  1073. {
  1074.     pieceVisible = flag;
  1075.     return self;
  1076. }
  1077. d351 4
  1078. a354 5
  1079. - setScoreKeeper:keeper
  1080. {
  1081.     scoreKeeper = keeper;
  1082.     return self;
  1083. }
  1084. d356 5
  1085. a360 1
  1086. double newDelay(float level)
  1087. d362 1
  1088. a362 44
  1089.     return 0.5 - 0.1 * sqrt(2.5 * level);
  1090. }
  1091.  
  1092. - newGame:(int)theLevel
  1093. {
  1094.     [[self setBitmap:nil] display];
  1095.     [window makeFirstResponder:self];
  1096.     [self setPieceVisible:YES];
  1097.     [thePiece reset:self
  1098.        piece:((showNext) ? [showNext pieceInfo] : PIECE_INFO_NULL)];
  1099.     [self display];
  1100.     level = (float)theLevel;
  1101.     teDelay = newDelay(level);
  1102.     [self startTimedEntry];
  1103.     active = YES;
  1104.     return self;
  1105. }
  1106.  
  1107.  
  1108. - pause:sender
  1109. {
  1110.     [window makeFirstResponder:window];
  1111.     active = NO;
  1112.     return [self stopTimedEntry];
  1113. }
  1114.  
  1115.  
  1116. - continue:sender
  1117. {
  1118.     active = YES;
  1119.     [window makeFirstResponder:self];
  1120.     return [self startTimedEntry];
  1121. }
  1122.  
  1123. - stop:sender
  1124. {
  1125.     active = NO;
  1126.     [window makeFirstResponder:window];
  1127.     return [self stopTimedEntry];
  1128. }
  1129. #ifdef FOO
  1130. static id newBitmap()
  1131. {
  1132.     char *bitmapName;
  1133. d364 1
  1134. a364 16
  1135.     switch (random() % NUM_BITMAPS) {
  1136.     case 0:
  1137.         bitmapName = "Block1";
  1138.         break;
  1139.     case 1:
  1140.         bitmapName = "Block2";
  1141.         break;
  1142.     case 2:
  1143.         bitmapName = "Block3";
  1144.         break;
  1145.     default:
  1146.         bitmapName = "Block4";
  1147.     }
  1148.     return [NXImage findImageNamed:bitmapName];
  1149. }
  1150. #endif
  1151. d366 2
  1152. a367 9
  1153. static void animateGameOver(id self)
  1154. {
  1155.     NXSize tmpSize;
  1156.     id anmGameOver;
  1157.     NXRect dRect, uRect;
  1158.     
  1159.     tmpSize.height = GAMEOVER_BMAP_H;
  1160.     tmpSize.width = self->insetBounds.size.width;
  1161.     anmGameOver = [[NXImage alloc] initSize:&tmpSize];
  1162. d369 1
  1163. a369 39
  1164.     // Composite "Game Over" to a window
  1165.     [anmGameOver lockFocus];
  1166.     PSsetalpha(0.0);
  1167.     PSrectfill(0.0, 0.0, self->insetBounds.size.width, GAMEOVER_BMAP_H);
  1168.     PSsetalpha(1.0);
  1169.     PSgameover(self->insetBounds.size.width);
  1170.     [anmGameOver unlockFocus];
  1171.     
  1172.     [self getRect:&dRect for:(int)(TETRIS_ROWS / 2) :0];
  1173.     [self getRect:&uRect for:TETRIS_ROWS - 1 :TETRIS_COLUMNS - 1];
  1174.     NXUnionRect(&uRect, &dRect);
  1175.     [self->anmBitmap lockFocus];
  1176.     [self drawSelf:&dRect :1];
  1177.     [self->anmBitmap unlockFocus];
  1178.     
  1179.     NXSetRect(&uRect, dRect.origin.x, uRect.origin.y,
  1180.                  dRect.size.width, GAMEOVER_BMAP_H);
  1181.     [self lockFocus];
  1182.     NXRectClip(&dRect);
  1183.     while (uRect.origin.y - ANM_GAMEOVER_DELTA >= dRect.origin.y) {
  1184.         uRect.origin.y -= ANM_GAMEOVER_DELTA;
  1185.         [anmGameOver composite:NX_SOVER toPoint:&uRect.origin];
  1186.         [self->window flushWindow];
  1187.         NXPing();
  1188.         [self->anmBitmap composite:NX_COPY fromRect:&uRect toPoint:&uRect.origin];
  1189.     }
  1190.     [anmGameOver composite:NX_SOVER toPoint:&uRect.origin];
  1191.     [self unlockFocus];
  1192.     
  1193.     [anmGameOver free];
  1194. }
  1195.  
  1196. void teHandler(DPSTimedEntry teNum, double now, id self)
  1197. {
  1198.     id thePiece = self->thePiece;
  1199.     static int downWait = 0;
  1200.     
  1201.     if (![thePiece down:self]) {
  1202.         if (++downWait >= self->level) {
  1203. d376 4
  1204. a379 4
  1205.             if (self->scoreKeeper) {
  1206.                 [self->scoreKeeper addScore:[thePiece points]];
  1207.                 self->level += (MAX_LEVEL - self->level) / 400.0;
  1208.                 self->teDelay = newDelay(self->level);
  1209. d381 2
  1210. a382 2
  1211.             if ([thePiece reset:self piece:((self->showNext) ?
  1212.                                       [self->showNext pieceInfo] : PIECE_INFO_NULL)])
  1213. d385 3
  1214. a387 3
  1215.                 animateGameOver(self);
  1216.                 [self->window makeFirstResponder:self->window];
  1217.                 self->active = NO;
  1218. d391 4
  1219. a394 2
  1220.     } else
  1221.       downWait = 0;
  1222. d397 6
  1223. d405 5
  1224. a409 6
  1225.     if (!teRunning) {
  1226.          timedEntryNum = DPSAddTimedEntry(teDelay, (DPSTimedEntryProc)teHandler,
  1227.                                                      self, NX_BASETHRESHOLD);
  1228.          teRunning = YES;
  1229.     }
  1230.     return self;
  1231. d421 3
  1232. @
  1233.